// Copyright 2016 The G3N Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package math32 implements basic math functions which operate
// directly on T numbers without casting and contains
// types of common entities used in 3D Graphics such as vectors,
// matrices, quaternions and others.
package mathx

import (
	"math"
)

const Pi = math.Pi
const degreeToRadiansFactor = math.Pi / 180
const radianToDegreesFactor = 180.0 / math.Pi

var Infinity = math.Inf(1)

// DegToRad converts a number from degrees to radians
func DegToRad[T Float](degrees T) T {

	return T(float64(degrees) * degreeToRadiansFactor)
}

// RadToDeg converts a number from radians to degrees
func RadToDeg[T Float](radians T) T {

	return T(float64(radians) * radianToDegreesFactor)
}

// Clamp clamps x to the provided closed interval [a, b]
func Clamp[T Float](x, a, b T) T {

	if x < a {
		return a
	}
	if x > b {
		return b
	}
	return x
}

// ClampInt clamps x to the provided closed interval [a, b]
func ClampInt(x, a, b int) int {

	if x < a {
		return a
	}
	if x > b {
		return b
	}
	return x
}

func Abs[T Float](v T) T {
	return T(math.Abs(float64(v)))
}

func Acos[T Float](v T) T {
	return T(math.Acos(float64(v)))
}

func Asin[T Float](v T) T {
	return T(math.Asin(float64(v)))
}

func Atan[T Float](v T) T {
	return T(math.Atan(float64(v)))
}

func Atan2[T Float](y, x T) T {
	return T(math.Atan2(float64(y), float64(x)))
}

func Ceil[T Float](v T) T {
	return T(math.Ceil(float64(v)))
}

func Cos[T Float](v T) T {
	return T(math.Cos(float64(v)))
}

func Floor[T Float](v T) T {
	return T(math.Floor(float64(v)))
}

func Inf[T Float](sign int) T {
	return T(math.Inf(sign))
}

func Round[T Float](v T) T {
	return T(Floor(float64(v) + 0.5))
}

func IsNaN[T Float](v T) bool {
	return math.IsNaN(float64(v))
}

func Sin[T Float](v T) T {
	return T(math.Sin(float64(v)))
}

func Sqrt[T Float](v T) T {
	return T(math.Sqrt(float64(v)))
}

func Max[T Float](a, b T) T {
	return T(math.Max(float64(a), float64(b)))
}

func Min[T Float](a, b T) T {
	return T(math.Min(float64(a), float64(b)))
}

func Mod[T Float](a, b T) T {
	return T(math.Mod(float64(a), float64(b)))
}

func NaN[T Float]() T {
	return T(math.NaN())
}

func Pow[T Float](a, b T) T {
	return T(math.Pow(float64(a), float64(b)))
}

func Tan[T Float](v T) T {
	return T(math.Tan(float64(v)))
}
